// todo:
/**
 * 1. 通过 reactive 创建响应式对象  row(target) { age:3 }
 * 2. 通过 watchEffect 函数 , 注册要被触发(get set 触发)的函数
 * 3. 改变row 对象的属性时候 重新触发watchEffect函数
 */
// process:
/**
 * 1. 创建响应式类 Dep,存放响应函数
 * 2. 创建 reactive 响应对象
 *      2.1 通过 全局 targetMap存放{ row-->depsMap } ,depsMap存放{ key-->dep } ,来绑定 (target,key) --> dep
 * 3. 通过 watchEffect 注册要被触发(get set 触发)的函数
 *      3.1 重置activeEffect（拷贝要被放入effects的函数） , 触发effect函数 , 因为触发了函数
 *          函数内部的响应式对象被get触发, 该dep收集响应响应函数放到effects队列里面
 * 4. 改变 响应对象的属性值 , 触发set方法 , dep执行notify让所有队列里面的函数遍历执行。
 *
 */

// coding
// 用这个来存对应的响应数据相关的依赖（info.name ---> 绑定name 改变时候要触发的effect）

debugger;
class Dep {
  // 放着所有要被触发的函数
  constructor() {
    this.effects = new Set();
  }

  //   把effect放进队列
  depend() {
    if (activeEffect) {
      this.effects.add(activeEffect);
    }
  }

  //   触发
  notify() {
    this.effects.forEach((effect) => {
      effect();
    });
  }
}

// watchEffect 调用一次（同时把节点绑定get和set）
let activeEffect = null;
function watchEffect(effect) {
  activeEffect = effect;
  //   这里面调用了一次effect 所以 definexxx的get方法被调用了 ,进而将依赖放进对应的队列了
  effect();
  activeEffect = null;
}

/**
 * @author lwt
 * @param { Object } target
 * @param { object | string | number... } key
 * @returns { Dep }
 */
let targetMap = new WeakMap();
function getDep(target, key) {
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    depsMap = new Map();
    targetMap.set(target, depsMap);
  }

  let dep = depsMap.get(key);
  if (!dep) {
    dep = new Dep();
    depsMap.set(key, dep);
  }
  return dep;
}

/**
 * @author lwt
 * @param { object } row
 * @returns { object }
 */
function reactive(row) {
  // 遍历row的属性
  for (const key in row) {
    if (Object.hasOwnProperty.call(row, key)) {
      // 不直接在下面get return row[key]会造成循环调用 所以拷贝一份
      let value = row[key];
      let dep = getDep(row, key);
      Object.defineProperty(row, key, {
        //   每次获取时候都把当前的依赖放到effects
        get() {
          dep.depend();
          return value;
        },
        set(val) {
          if (value !== val) {
            value = val;
            dep.notify();
          }
        },
      });
    }
  }
  return row;
}

// 绑定row.info和对应的dep,同时绑定defineProperty到info
let row = reactive({
  info: "我是响应式数据",
  age: 1,
  height: 100,
});

let b;
// 收集effect函数,同时触发一次（再次强调 该次触发是因为被get找到然后depend进去的）
watchEffect(function () {
  b = row.age;
  console.log("row响应age", b);
});
watchEffect(function () {
  b = row.height;
  console.log("row响应height", b);
});
row.age = 2;
row.height = 200;
